package com.tianji.learning.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearningPlanDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.domain.vo.LearningLessonVO;
import com.tianji.learning.domain.vo.LearningPlanPageVO;
import com.tianji.learning.domain.vo.LearningPlanVO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.PlanStatus;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.learning.service.ILearningRecordService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;

import static io.lettuce.core.GeoArgs.Sort.desc;


@Service
@RequiredArgsConstructor
@Slf4j
public class LearningLessonServiceImpl extends ServiceImpl<LearningLessonMapper, LearningLesson> implements ILearningLessonService {

    private final LearningLessonMapper learningLessonMapper;

    private final CourseClient courseClient;

    private final CatalogueClient catalogueClient;

    private final ILearningRecordService learningRecordService;

    @Override
    public PageDTO<LearningLessonVO> queryMyLesson(PageQuery pageQuery) {
        Long userId = UserContext.getUser();
        // select * from LearningLesson where user_id = userId limit from,pageSize
        Page<LearningLesson> page = lambdaQuery().eq(LearningLesson::getUserId, userId).page(pageQuery.toMpPage("latest_learn_time", false));
        List<LearningLesson> records = page.getRecords();
        if (CollUtils.isEmpty(records)) {
            return PageDTO.empty(page);
        }

        //将课程信息转为map，key为课程id，value为课程本身
        Map<Long, CourseSimpleInfoDTO> simpleInfoMap = queryCourseToMap(records);

        List<LearningLessonVO> learningLessonVOList = new ArrayList<>(records.size());
        for (LearningLesson record : records) {
            LearningLessonVO vo = BeanUtils.copyBean(record, LearningLessonVO.class);
            CourseSimpleInfoDTO cInfo = simpleInfoMap.get(record.getCourseId());
            if (cInfo == null) {
                continue;
            }
            vo.setCourseName(cInfo.getName());
            vo.setSections(cInfo.getSectionNum());
            vo.setCourseCoverUrl(cInfo.getCoverUrl());
            learningLessonVOList.add(vo);
        }

        return PageDTO.of(page, learningLessonVOList);
    }

    @Override
    @Transactional
    public void addCourseToLesson(Long userId, List<Long> courseIds) {
        if (userId == null || CollUtils.isEmpty(courseIds)) {
            throw new BadRequestException("用户id和课程id不能为空");
        }
        List<CourseSimpleInfoDTO> simpleInfoList = courseClient.getSimpleInfoList(courseIds);
        if (CollUtils.isEmpty(simpleInfoList)) {
            log.error("课程信息不存在，无法添加");
            return;
        }
        List<LearningLesson> learningLessonList = new ArrayList<>(simpleInfoList.size());
        for (CourseSimpleInfoDTO cInfo : simpleInfoList) {
            LearningLesson learningLesson = new LearningLesson();
            Integer expire = cInfo.getValidDuration();
            if (expire != null) {
                LocalDateTime now = LocalDateTime.now();
                learningLesson.setExpireTime(now.plusMonths(expire));
            }
            learningLesson.setUserId(userId);
            learningLesson.setCourseId(cInfo.getId());
            learningLessonList.add(learningLesson);
        }
        saveBatch(learningLessonList);
    }

    @Override
    public LearningLessonVO queryLeastLearning() {
        Long userId = UserContext.getUser();

        LearningLesson ll = lambdaQuery().eq(LearningLesson::getUserId, userId).eq(LearningLesson::getStatus, LessonStatus.LEARNING).orderByDesc(LearningLesson::getLatestLearnTime).one();
        if (ll == null) {
            return null;
        }

        LearningLessonVO vo = BeanUtils.copyBean(ll, LearningLessonVO.class);

        CourseFullInfoDTO cInfo = courseClient.getCourseInfoById(ll.getCourseId(), true, false);
        if (cInfo == null) {
            throw new BadRequestException("课程不存在");
        }
        vo.setCourseName(cInfo.getName());
        vo.setCourseCoverUrl(cInfo.getCoverUrl());
        vo.setSections(cInfo.getSectionNum());

        Long count = lambdaQuery().eq(LearningLesson::getUserId, userId).count();
        vo.setCourseAmount(count.intValue());

        //根据章节id查询章节信息
        List<CataSimpleInfoDTO> cataSimpleInfoDTOS = catalogueClient.batchQueryCatalogue(Collections.singletonList(ll.getLatestSectionId()));
        if (!CollUtils.isEmpty(cataSimpleInfoDTOS)) {
            CataSimpleInfoDTO cataSimpleInfoDTO = cataSimpleInfoDTOS.get(0);
            vo.setLatestSectionName(cataSimpleInfoDTO.getName());
            vo.setLatestSectionIndex(cataSimpleInfoDTO.getCIndex());
        }

        return vo;
    }

    @Override
    public void deleteByCourseId(Long userId, Long courseId) {
        if (courseId == null) {
            throw new BadRequestException("课程id不能为空");
        }
        if (userId == null) {
            userId = UserContext.getUser();
        }
        log.info("需要删除用户{}的课程{}", userId, courseId);
        boolean removed =
                remove(new LambdaQueryWrapper<LearningLesson>()
                        .eq(LearningLesson::getUserId, userId)
                        .eq(LearningLesson::getStatus, LessonStatus.EXPIRED)
                        .eq(LearningLesson::getCourseId, courseId));

        if (!removed) {
            log.error("课表信息不存在，无法删除");
        }
    }

    @Override
    public Long validCourseById(Long courseId) {
        if (courseId == null) {
            return null;
        }
        Long userId = UserContext.getUser();
        LearningLesson lesson = lambdaQuery().eq(LearningLesson::getUserId, userId).eq(LearningLesson::getCourseId, courseId).one();
        if (lesson == null || lesson.getExpireTime().isBefore(LocalDateTime.now())) {
            return null;
        }
        return lesson.getId();
    }

    @Override
    public LearningLessonVO getLessonByCourseId(Long courseId) {
        if (courseId == null) {
            return null;
        }
        Long userId = UserContext.getUser();
        LearningLesson lesson = getLessonByUserIdAndCourseId(userId, courseId);
        if (lesson == null) {
            return null;
        }
        LearningLessonVO vo = BeanUtils.copyBean(lesson, LearningLessonVO.class);
        return vo;
    }

    @Override
    public LearningLesson getLessonByUserIdAndCourseId(Long userId, Long courseId) {
        return lambdaQuery().eq(LearningLesson::getUserId, userId).eq(LearningLesson::getCourseId, courseId).one();
    }

    //从课表中查找我的学习计划
    @Override
    public LearningPlanPageVO queryLearningPlan(PageQuery pageQuery) {
        DateTime date = DateUtil.date();
        DateTime startTime = DateUtil.beginOfWeek(date);
        DateTime endTime = DateUtil.endOfWeek(date);
        Long userId = UserContext.getUser();

        //查找有学习计划的课表集合
        List<LearningLesson> lessonList = queryPlanFromLesson(userId).list();

        if (CollUtils.isEmpty(lessonList)) {
            return null;
        }

        //对某个字段求和 mapToInt()/mapToLong +sum()
        int weekTotalPlan = lessonList.stream().mapToInt(LearningLesson::getWeekFreq).sum();

        List<LearningPlanVO> learningPlanList = BeanUtils.copyList(lessonList, LearningPlanVO.class);
        //遍历lessonList 根据courseId查询 课程名称，总数 根据lessonId查询本周学习记录
        Map<Long, CourseSimpleInfoDTO> cInfoMap = queryCourseToMap(lessonList);
        if (cInfoMap == null) {
            return null;
        }

        Set<Long> lessonIds = lessonList.stream().map(LearningLesson::getId).collect(Collectors.toSet());
        List<LearningRecord> records = learningRecordService
                .lambdaQuery()
                .eq(LearningRecord::getUserId, userId)
                .eq(LearningRecord::getFinished, true)
                .in(LearningRecord::getLessonId, lessonIds)
                .gt(LearningRecord::getFinishTime, startTime)
                .lt(LearningRecord::getFinishTime, endTime)
                .list();
        if (CollUtils.isEmpty(records)) {
            return null;
        }
        int weekLearnedTotal = records.size();
        //课程对应已学习的章节数
        Map<Long, Long> lessonGroupMap = records.stream().collect(Collectors.groupingBy(LearningRecord::getLessonId, Collectors.counting()));
        if (CollUtils.isEmpty(lessonGroupMap)) {
            return null;
        }
        LearningPlanPageVO learningPlanPageVO = new LearningPlanPageVO();
        learningPlanPageVO.setWeekTotalPlan(weekTotalPlan);
        learningPlanPageVO.setWeekFinished(weekLearnedTotal);

        // 处理分页数据
        // 分页查询课表信息以及学习计划信息
        Page<LearningLesson> p = new Page<>(pageQuery.getPageNo(), pageQuery.getPageSize(), lessonList.size());
        List<LearningPlanVO> recordList = CollUtils.sub(learningPlanList, pageQuery.from(), pageQuery.from() + pageQuery.getPageSize());
        if (CollUtils.isEmpty(recordList)) {
            return learningPlanPageVO;
        }

        //遍历学习计划课程 填充属性
        for (LearningPlanVO learningPlanVO : recordList) {
            CourseSimpleInfoDTO cInfo = cInfoMap.get(learningPlanVO.getCourseId());
            if (cInfo != null) {
                learningPlanVO.setCourseName(cInfo.getName());
                learningPlanVO.setSections(cInfo.getSectionNum());
            }
            Long weekLearned = lessonGroupMap.get(learningPlanVO.getId());
            if (weekLearned != null) {
                learningPlanVO.setWeekLearnedSections(weekLearned.intValue());
            }
        }

        return learningPlanPageVO.pageInfo(p.getTotal(), p.getPages(), recordList);
    }

    private LambdaQueryChainWrapper<LearningLesson> queryPlanFromLesson(Long userId){
        LambdaQueryChainWrapper<LearningLesson> wrapper = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
                .in(LearningLesson::getStatus, LessonStatus.NOT_BEGIN, LessonStatus.LEARNING);
        return wrapper;
    }

    @Override
    public void updateLearningPlan(LearningPlanDTO learningPlanDTO) {
        Long userId = UserContext.getUser();
        LearningLesson lesson = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, learningPlanDTO.getCourseId())
                .one();
        if (lesson == null) {
            log.error("课程信息不存在");
            return;
        }
        Integer status = lesson.getStatus().getValue();
        boolean update = lambdaUpdate()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, learningPlanDTO.getCourseId())
                .set(status == PlanStatus.NO_PLAN.getValue(), LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
                .set(LearningLesson::getWeekFreq, learningPlanDTO.getFreq())
                .update();
        if (!update) {
            log.error("用户{}的课表{}更新学习计划失败", userId, learningPlanDTO.getCourseId());
        }
    }

    //根据课表查询出课程并转为map（key为课程id，value为课程本身）
    public Map<Long, CourseSimpleInfoDTO> queryCourseToMap(List<LearningLesson> records) {
        if (CollUtils.isEmpty(records)) {
            throw new BadRequestException("课表信息不能为空");
        }
        Set<Long> courseIds = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toSet());
        List<CourseSimpleInfoDTO> cInfos = courseClient.getSimpleInfoList(courseIds);
        if (CollUtils.isEmpty(cInfos)) {
            throw new BadRequestException("课程信息不存在");
        }
        Map<Long, CourseSimpleInfoDTO> cInfoMap = cInfos.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, v -> v));
        return cInfoMap;

    }
}
